package busterminal.persistence.jdbc;

import busterminal.entity.BusModel;
import busterminal.entity.BusModelImplementation;
import busterminal.entity.service.VehicleType;
import busterminal.exception.BusinessException;
import busterminal.exception.DatabaseException;
import busterminal.persistence.BusModelDAO;
import busterminal.persistence.jdbc.proxy.BusModelProxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * Реализация интерфейса Data Access Object для модели автобуса
 */
public class JdbcBusModelDAO extends AbstractJdbcDAO<BusModel> implements BusModelDAO {

    /**
     * Добавить модель автобуса в базу данных
     * @param busModel ссылка на модель автобуса
     */
    @Override
    public void create(BusModel busModel) {
        busModel.setId(getNextId());

        Connection cn = getConnection();
        PreparedStatement st = null;
        try {
            st = cn.prepareStatement("INSERT INTO BusModel (Id, ModelName, VehicleType) VALUES (?, ?, ?)");
            st.setInt(1, busModel.getId());
            st.setString(2, busModel.getModelName());
            st.setString(3, busModel.getVehicleType().toString());
            st.execute();
        } catch (SQLException e) {
            throw new DatabaseException("Cann't create new bus model with name " + busModel.getModelName() + " and with vehicle type " + busModel.getVehicleType(), e);
        } finally {
            try {
                st.close();
            } catch (SQLException ex) {
                System.err.println("Cann't close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Прочитать модель автобуса из базы данных
     * @param id идентификатор модели автобуса
     * @return ссылка на модель автобуса
     */
    @Override
    public BusModel read(Integer id) {
        Connection cn = getConnection();
        Statement st = null;
        ResultSet rs = null;
        BusModel busModel = null;
        try {
            st = cn.createStatement();
            rs = st.executeQuery("SELECT Id, ModelName, VehicleType FROM BusModel WHERE Id=" + id);
            if (rs.next()) {
                busModel = new BusModelImplementation();
                busModel.setId(rs.getInt("Id"));
                busModel.setModelName(rs.getString("ModelName").trim());
                busModel.setVehicleType(VehicleType.valueOf(rs.getString("VehicleType").trim()));
                }
        } catch (SQLException e) {
            throw new DatabaseException("Cann't read bus model with ID=" + id, e);
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (st != null) {
                    st.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cann't close statement");
                ex.printStackTrace(System.err);
            }
        }
        if(busModel == null) {
            throw new BusinessException("Bus model with ID=" + id + " not found");
        }
        return busModel;
    }

    /**
     * Обновить сведения о модели автобуса в базе данных
     * @param busModel ссылка на модель автобуса
     */
    @Override
    public void update(BusModel busModel) {
        Connection cn = getConnection();
        PreparedStatement st = null;
        try {
            st = cn.prepareStatement("UPDATE BusModel SET ModelName=?, VehicleType=? where Id=?");
            st.setString(1, busModel.getModelName());
            st.setString(2, busModel.getVehicleType().toString());
            st.setInt(3, busModel.getId());
            st.execute();            
        } catch (SQLException e) {
            throw new DatabaseException("Cann't update bus model with Id=" + busModel.getId(), e);
        } finally {
            try {
                st.close();
            } catch (SQLException ex) {
                System.err.println("Cann't close statement");
                ex.printStackTrace(System.err);
            }
        }
    }

    /**
     * Удалить модель автобуса из базы данных
     * @param busModel ссылка на модель автобуса
     */
    @Override
    public void delete(BusModel busModel) {
        delete(busModel.getId());
    }

    /**
     * Удалить модель автобуса из базы данных
     * @param id идентификатор модели автобуса
     */
    @Override
    public void delete(Integer id) {
        Connection connection = getConnection();
        PreparedStatement preparedStatement = null;
        try {
            preparedStatement = connection.prepareStatement("DELETE FROM BusModel WHERE Id=?");
            preparedStatement.setInt(1, id);
            preparedStatement.execute();
        } catch (SQLException e) {
            throw new DatabaseException("Cannot delete bus model with Id=" + id, e);
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cannot close statement");
                ex.printStackTrace(System.err);
            }
        }
    }
    
    /**
     * Получить список всех моделей автобусов из базы данных
     * @return список моделей автобусов
     */
    @Override
    public List<BusModel> findAll() {
        Connection cn = getConnection();
        Statement st = null;
        ResultSet rs = null;
        List<BusModel> busModelList = new ArrayList<BusModel>();
        try {
            st = cn.createStatement();
            rs = st.executeQuery("SELECT Id FROM BusModel");
            while (rs.next()) {
                BusModel busModel = new BusModelProxy();
                busModel.setId(rs.getInt("Id"));
                busModelList.add(busModel);
            }
        } catch (SQLException e) {
            throw new DatabaseException("Cann't read bus model list", e);
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (st != null) {
                    st.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cann't close statement");
                ex.printStackTrace(System.err);
            }
        }
        if(busModelList == null) {
            throw new BusinessException("Bus model list is empty");
        }              
        return busModelList;
    }

    /**
     * Найти модель автобуса по названию модели
     * @param modelName название модели
     * @return ссылка на модель автобуса
     */
    @Override
    public BusModel findByModelName(String modelName) {
        Connection cn = getConnection();
        PreparedStatement st = null;
        ResultSet rs = null;
        BusModel busModel = null;
        try {
            st = cn.prepareStatement("SELECT Id, ModelName, VehicleType FROM BusModel WHERE ModelName=?");
            st.setString(1, modelName);
            rs = st.executeQuery();
            if (rs.next()) {
                busModel = new BusModelImplementation();
                busModel.setId(rs.getInt("Id"));
                busModel.setModelName(rs.getString("ModelName".trim()));
                busModel.setVehicleType(VehicleType.valueOf(rs.getString("VehicleType")));
            }
        } catch (SQLException e) {
            throw new DatabaseException("Cann't read bus model with name " + modelName, e);
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (st != null) {
                    st.close();
                }
            } catch (SQLException ex) {
                System.err.println("Cann't close statement");
                ex.printStackTrace(System.err);
            }
        }
        if(busModel == null) {
            throw new BusinessException("Bus model with name " + modelName + " not found");
        }      
        return busModel;
    }
}
